import json

import flask_login
import flask_rbac
from flask import Flask, jsonify, make_response
from flask_cors import CORS
from flask_login import LoginManager
from flask_rbac import RBAC

from conf.redis_cnx import RedisCnxPool
from service.user_role import UserRole
from web.const import StatusCode

redis_conn = RedisCnxPool().get_conn()


class FlaskIni:
    app = Flask(__name__)

    # Only allowing rules can access the resources.
    # This means, all deny rules and rules you did not add cannot access the resources.
    app.config['RBAC_USE_WHITE'] = True

    CORS(app)

    rbac = RBAC(app)

    def get_app(self):
        return self.app

    def get_rbac(self):
        return self.rbac

    @staticmethod
    def get_role_obj(role_name):
        return role_map[role_name]


app = FlaskIni().get_app()
rbac = FlaskIni().get_rbac()


class Role(flask_rbac.RoleMixin):
    pass


class User(flask_rbac.UserMixin, flask_login.UserMixin):
    id = None
    pass


rbac.set_role_model(Role)
rbac.set_user_model(User)

login_manager = LoginManager()
login_manager.init_app(app)


@login_manager.request_loader
def load_user_from_request(request):
    # try to login using the api_key url arg
    api_key = request.headers.get('Authorization')
    if api_key:
        try:
            json_value = json.loads(str(redis_conn.get(api_key), encoding='utf-8'))
            if json_value is None:
                return None

            user = User(roles=[FlaskIni.get_role_obj(json_value['role_name'])])
            if user:
                return user
        except:
            return None
    return None


@login_manager.unauthorized_handler
def unauthorized_handler():
    return jsonify({'status': StatusCode.UNAUTHORIZED_CODE,
                    'message': 'Unauthorized login',
                    'payload': ''})


rbac.set_hook(lambda: make_response(
    jsonify({'status': StatusCode.PERMISSION_DENIED_CODE,
             'message': 'Permission denied',
             'payload': ''})))

all_roles = UserRole.query_all_roles()
role_map = {role: Role(role) for role in all_roles}

role_map['编辑员'].add_parents(role_map['小萌新'])
role_map['审查员'].add_parents(role_map['小萌新'])
role_map['管理员'].add_parents(role_map['编辑员'], role_map['审查员'])
